/**
 * new map()
 * clear 从映射中移除所有元素
 * delete 从映射中移除指定的元素
 * forEach 对映射中的每个元素执行指定操作
 * get 返回映射中的指定元素
 * has 如果映射包含指定元素，则返回true
 * set 添加一个新元素到映射
 * toString 返回映射的字符串表示形式
 * valueOf 返回指定对象的原始值
 */

/**
 * 需求：
 * 能满足页面之间的通讯
 * 能满足页面和组件(component)之间的通讯
 * 能满足组件(component)之间的通讯
 * 为了能正确响应到自己想要的事件，需要通过一个key来标识每一个事件
 * 而且不同的页面可以使用相同的key来作为事件标识
 */

/**
 * 原理
 * 系统中所有的订阅的消息通过一个全局的字典（Map）来存储，其中的key是事件标识，每个key对应一个数组（这里用数组而不用单个对象是为了能在不同的页面能用相同的key订阅事件，因为有时候一个页面发布消息需要多个页面响应），数组中每个元素是一个对象，其中target表示订阅消息的发起者，callback表示对应发起者的回调函数。然后发布消息的时候直接通过对应的key来拿到消息队列，然后遍历队列发布消息。
 */

let events = new Map()
/**
 * 消息订阅
 * key：消息标识
 * target：消息发起者，用来区分相同key不同的消息
 * callback：回调函数
 */
function sub(key, target, callback) {
  // 消息对象
  let eobj = {
    "target": target,
    "callback": callback
  }
  // 先通过key拿到对应的消息队列
  let value = events.get(key)
  // 当前key已存在消息队列，说明是不同页面相同的key的消息订阅
  if (Array.isArray(value)) {
    // 过滤出消息发起者不同的消息，相当于覆盖key和target都一样的消息
    value = value.filter(function (e) {
      return e.target != target
    })
    // 过滤出的队列重新插入此次订阅的消息
    value.push(eobj)
    events.set(key, value)
  } else {
    // 不是队列表示字典中没有包含当前key的消息，直接插入
    events.set(key, [eobj])
  }
  console.log("EventBus Subscribe: ", events)
}
/**
 * 消息发布
 * key：消息标识
 * data：回调数据
 */
function pub(key, data) {
  // 通过key拿到消息队列
  let value = events.get(key)
  console.log("EventBus Publish: ", value)
  // 如果队列存在则遍历队列，然后调用消息发起者的回调函数，并将data数据进行回调
  if (Array.isArray(value)) {
    value.map(function (e) {
      let target = e.target
      let callback = e.callback
      callback.call(target, data)
    })
  }
}
/**
 * 取消订阅
 * key：消息标识
 * target：消息发起者，用来区分相同key不同的消息
 */
function cancel(key, target) {
  const haskey = events.has(key)
  // 是否存在此消息队列
  if (haskey) {
    let value = events.get(key)
    if (Array.isArray(value)) {
      // 如果队列中只有一条数据直接删除
      if (value.length === 1) {
        events.delete(key)
      } else {
        // 如果队列中存在多条数据则过滤出和当前取消订阅target不同的消息然后重新设置到key的消息队列中
        value = value.filter(function (e) {
          return e.target != target
        })
        events.set(key, value)
      }
    }
  }
  console.log("EventBus Cancel: ", events)
}

if (wx) {
  wx.sub = sub
  wx.pub = pub
  wx.cancel = cancel
}

module.exports = {
  sub, // 消息订阅
  pub, // 消息发布
  cancel // 取消订阅
}